use libcraft_blocks::BlockState;
use libcraft_items::Item;
use ordinalizer::Ordinal;
use serde::{Deserialize, Serialize};

#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[repr(C)]
pub struct Particle {
    pub kind: ParticleKind,
    pub offset_x: f32,
    pub offset_y: f32,
    pub offset_z: f32,
    pub count: i32,
}

/// This is an enum over the kinds of particles
/// listed on [the Particle data type](https://wiki.vg/index.php?title=Protocol&oldid=16400#Particle).
/// Some particles are missing on that list (SoulFlame, Soul, BubblePop and the crying obsidian ones)
/// So they've been added
#[derive(Copy, Clone, Debug, PartialEq, Ordinal, Serialize, Deserialize)]
#[repr(C)]
pub enum ParticleKind {
    AmbientEntityEffect,
    AngryVillager,
    Barrier,
    /// Block break particles
    Block(BlockState),
    Bubble,
    Cloud,
    Crit,
    DamageIndicator,
    DragonBreath,
    DrippingLava,
    FallingLava,
    LandingLava,
    DrippingWater,
    FallingWater,
    Dust {
        red: f32,
        green: f32,
        blue: f32,
        /// Will be clamped between 0.01 and 4.0.
        scale: f32,
    },
    Effect,
    ElderGuardian,
    EnchantedHit,
    Enchant,
    EndRod,
    EntityEffect,
    ExplosionEmitter,
    Explosion,
    FallingDust(BlockState),
    Firework,
    Fishing,
    Flame,
    SoulFireFlame,
    Soul,
    Flash,
    HappyVillager,
    Composter,
    Heart,
    InstantEffect,
    Item(Option<Item>), // TODO: Should be moved to Slot/ItemStack once it's done
    ItemSlime,
    ItemSnowball,
    LargeSmoke,
    Lava,
    Mycelium,
    Note,
    Poof,
    Portal,
    Rain,
    Smoke,
    Sneeze,
    Spit,
    SquidInk,
    SweepAttack,
    TotemOfUndying,
    Underwater,
    Splash,
    Witch,
    BubblePop,
    CurrentDown,
    BubbleColumnUp,
    Nautilus,
    Dolphin,
    CampfireCosySmoke,
    CampfireSignalSmoke,
    DrippingHoney,
    FallingHoney,
    LandingHoney,
    FallingNectar,
    Ash,
    CrimsonSpore,
    WarpedSpore,
    DrippingObsidianTear,
    FallingObsidianTear,
    LandingObsidianTear,
    ReversePortal,
    WhiteAsh,
}

impl ParticleKind {
    /// Returns the `id` property of this `ParticleKind`.
    pub fn id(&self) -> u32 {
        match self {
            ParticleKind::AmbientEntityEffect => 0,
            ParticleKind::AngryVillager => 1,
            ParticleKind::Barrier => 2,
            ParticleKind::Block(_) => 3,
            ParticleKind::Bubble => 4,
            ParticleKind::Cloud => 5,
            ParticleKind::Crit => 6,
            ParticleKind::DamageIndicator => 7,
            ParticleKind::DragonBreath => 8,
            ParticleKind::DrippingLava => 9,
            ParticleKind::FallingLava => 10,
            ParticleKind::LandingLava => 11,
            ParticleKind::DrippingWater => 12,
            ParticleKind::FallingWater => 13,
            ParticleKind::Dust { .. } => 14,
            ParticleKind::Effect => 15,
            ParticleKind::ElderGuardian => 16,
            ParticleKind::EnchantedHit => 17,
            ParticleKind::Enchant => 18,
            ParticleKind::EndRod => 19,
            ParticleKind::EntityEffect => 20,
            ParticleKind::ExplosionEmitter => 21,
            ParticleKind::Explosion => 22,
            ParticleKind::FallingDust(_) => 23,
            ParticleKind::Firework => 24,
            ParticleKind::Fishing => 25,
            ParticleKind::Flame => 26,
            ParticleKind::SoulFireFlame => 27,
            ParticleKind::Soul => 28,
            ParticleKind::Flash => 29,
            ParticleKind::HappyVillager => 30,
            ParticleKind::Composter => 31,
            ParticleKind::Heart => 32,
            ParticleKind::InstantEffect => 33,
            ParticleKind::Item(_) => 34,
            ParticleKind::ItemSlime => 35,
            ParticleKind::ItemSnowball => 36,
            ParticleKind::LargeSmoke => 37,
            ParticleKind::Lava => 38,
            ParticleKind::Mycelium => 39,
            ParticleKind::Note => 40,
            ParticleKind::Poof => 41,
            ParticleKind::Portal => 42,
            ParticleKind::Rain => 43,
            ParticleKind::Smoke => 44,
            ParticleKind::Sneeze => 45,
            ParticleKind::Spit => 46,
            ParticleKind::SquidInk => 47,
            ParticleKind::SweepAttack => 48,
            ParticleKind::TotemOfUndying => 49,
            ParticleKind::Underwater => 50,
            ParticleKind::Splash => 51,
            ParticleKind::Witch => 52,
            ParticleKind::BubblePop => 53,
            ParticleKind::CurrentDown => 54,
            ParticleKind::BubbleColumnUp => 55,
            ParticleKind::Nautilus => 56,
            ParticleKind::Dolphin => 57,
            ParticleKind::CampfireCosySmoke => 58,
            ParticleKind::CampfireSignalSmoke => 59,
            ParticleKind::DrippingHoney => 60,
            ParticleKind::FallingHoney => 61,
            ParticleKind::LandingHoney => 62,
            ParticleKind::FallingNectar => 63,
            ParticleKind::Ash => 64,
            ParticleKind::CrimsonSpore => 65,
            ParticleKind::WarpedSpore => 66,
            ParticleKind::DrippingObsidianTear => 67,
            ParticleKind::FallingObsidianTear => 68,
            ParticleKind::LandingObsidianTear => 69,
            ParticleKind::ReversePortal => 70,
            ParticleKind::WhiteAsh => 71,
        }
    }

    /// Gets a `Particle` by its `id`.
    ///
    /// For kinds like `ParticleKind::Block` that require additional data,
    /// this will return the "empty" variant.
    pub fn from_id(id: u32) -> Option<Self> {
        match id {
            0 => Some(ParticleKind::AmbientEntityEffect),
            1 => Some(ParticleKind::AngryVillager),
            2 => Some(ParticleKind::Barrier),
            3 => Some(ParticleKind::Block(BlockState::from_id(0).unwrap())),
            4 => Some(ParticleKind::Bubble),
            5 => Some(ParticleKind::Cloud),
            6 => Some(ParticleKind::Crit),
            7 => Some(ParticleKind::DamageIndicator),
            8 => Some(ParticleKind::DragonBreath),
            9 => Some(ParticleKind::DrippingLava),
            10 => Some(ParticleKind::FallingLava),
            11 => Some(ParticleKind::LandingLava),
            12 => Some(ParticleKind::DrippingWater),
            13 => Some(ParticleKind::FallingWater),
            14 => Some(ParticleKind::Dust {
                red: 0.0,
                blue: 0.0,
                green: 0.0,
                scale: 0.0,
            }),
            15 => Some(ParticleKind::Effect),
            16 => Some(ParticleKind::ElderGuardian),
            17 => Some(ParticleKind::EnchantedHit),
            18 => Some(ParticleKind::Enchant),
            19 => Some(ParticleKind::EndRod),
            20 => Some(ParticleKind::EntityEffect),
            21 => Some(ParticleKind::ExplosionEmitter),
            22 => Some(ParticleKind::Explosion),
            23 => Some(ParticleKind::FallingDust(BlockState::from_id(0).unwrap())),
            24 => Some(ParticleKind::Firework),
            25 => Some(ParticleKind::Fishing),
            26 => Some(ParticleKind::Flame),
            27 => Some(ParticleKind::SoulFireFlame),
            28 => Some(ParticleKind::Soul),
            29 => Some(ParticleKind::Flash),
            30 => Some(ParticleKind::HappyVillager),
            31 => Some(ParticleKind::Composter),
            32 => Some(ParticleKind::Heart),
            33 => Some(ParticleKind::InstantEffect),
            34 => Some(ParticleKind::Item(None)),
            35 => Some(ParticleKind::ItemSlime),
            36 => Some(ParticleKind::ItemSnowball),
            37 => Some(ParticleKind::LargeSmoke),
            38 => Some(ParticleKind::Lava),
            39 => Some(ParticleKind::Mycelium),
            40 => Some(ParticleKind::Note),
            41 => Some(ParticleKind::Poof),
            42 => Some(ParticleKind::Portal),
            43 => Some(ParticleKind::Rain),
            44 => Some(ParticleKind::Smoke),
            45 => Some(ParticleKind::Sneeze),
            46 => Some(ParticleKind::Spit),
            47 => Some(ParticleKind::SquidInk),
            48 => Some(ParticleKind::SweepAttack),
            49 => Some(ParticleKind::TotemOfUndying),
            50 => Some(ParticleKind::Underwater),
            51 => Some(ParticleKind::Splash),
            52 => Some(ParticleKind::Witch),
            53 => Some(ParticleKind::BubblePop),
            54 => Some(ParticleKind::CurrentDown),
            55 => Some(ParticleKind::BubbleColumnUp),
            56 => Some(ParticleKind::Nautilus),
            57 => Some(ParticleKind::Dolphin),
            58 => Some(ParticleKind::CampfireCosySmoke),
            59 => Some(ParticleKind::CampfireSignalSmoke),
            60 => Some(ParticleKind::DrippingHoney),
            61 => Some(ParticleKind::FallingHoney),
            62 => Some(ParticleKind::LandingHoney),
            63 => Some(ParticleKind::FallingNectar),
            64 => Some(ParticleKind::Ash),
            65 => Some(ParticleKind::CrimsonSpore),
            66 => Some(ParticleKind::WarpedSpore),
            67 => Some(ParticleKind::DrippingObsidianTear),
            68 => Some(ParticleKind::FallingObsidianTear),
            69 => Some(ParticleKind::LandingObsidianTear),
            70 => Some(ParticleKind::ReversePortal),
            71 => Some(ParticleKind::WhiteAsh),
            _ => None,
        }
    }
}

impl ParticleKind {
    /// Returns the `name` property of this `ParticleKind`.
    pub fn name(&self) -> &'static str {
        match self {
            ParticleKind::AmbientEntityEffect => "ambient_entity_effect",
            ParticleKind::AngryVillager => "angry_villager",
            ParticleKind::Barrier => "barrier",
            ParticleKind::Block(_) => "block",
            ParticleKind::Bubble => "bubble",
            ParticleKind::Cloud => "cloud",
            ParticleKind::Crit => "crit",
            ParticleKind::DamageIndicator => "damage_indicator",
            ParticleKind::DragonBreath => "dragon_breath",
            ParticleKind::DrippingLava => "dripping_lava",
            ParticleKind::FallingLava => "falling_lava",
            ParticleKind::LandingLava => "landing_lava",
            ParticleKind::DrippingWater => "dripping_water",
            ParticleKind::FallingWater => "falling_water",
            ParticleKind::Dust { .. } => "dust",
            ParticleKind::Effect => "effect",
            ParticleKind::ElderGuardian => "elder_guardian",
            ParticleKind::EnchantedHit => "enchanted_hit",
            ParticleKind::Enchant => "enchant",
            ParticleKind::EndRod => "end_rod",
            ParticleKind::EntityEffect => "entity_effect",
            ParticleKind::ExplosionEmitter => "explosion_emitter",
            ParticleKind::Explosion => "explosion",
            ParticleKind::FallingDust(_) => "falling_dust",
            ParticleKind::Firework => "firework",
            ParticleKind::Fishing => "fishing",
            ParticleKind::Flame => "flame",
            ParticleKind::SoulFireFlame => "soul_fire_flame",
            ParticleKind::Soul => "soul",
            ParticleKind::Flash => "flash",
            ParticleKind::HappyVillager => "happy_villager",
            ParticleKind::Composter => "composter",
            ParticleKind::Heart => "heart",
            ParticleKind::InstantEffect => "instant_effect",
            ParticleKind::Item(_) => "item",
            ParticleKind::ItemSlime => "item_slime",
            ParticleKind::ItemSnowball => "item_snowball",
            ParticleKind::LargeSmoke => "large_smoke",
            ParticleKind::Lava => "lava",
            ParticleKind::Mycelium => "mycelium",
            ParticleKind::Note => "note",
            ParticleKind::Poof => "poof",
            ParticleKind::Portal => "portal",
            ParticleKind::Rain => "rain",
            ParticleKind::Smoke => "smoke",
            ParticleKind::Sneeze => "sneeze",
            ParticleKind::Spit => "spit",
            ParticleKind::SquidInk => "squid_ink",
            ParticleKind::SweepAttack => "sweep_attack",
            ParticleKind::TotemOfUndying => "totem_of_undying",
            ParticleKind::Underwater => "underwater",
            ParticleKind::Splash => "splash",
            ParticleKind::Witch => "witch",
            ParticleKind::BubblePop => "bubble_pop",
            ParticleKind::CurrentDown => "current_down",
            ParticleKind::BubbleColumnUp => "bubble_column_up",
            ParticleKind::Nautilus => "nautilus",
            ParticleKind::Dolphin => "dolphin",
            ParticleKind::CampfireCosySmoke => "campfire_cosy_smoke",
            ParticleKind::CampfireSignalSmoke => "campfire_signal_smoke",
            ParticleKind::DrippingHoney => "dripping_honey",
            ParticleKind::FallingHoney => "falling_honey",
            ParticleKind::LandingHoney => "landing_honey",
            ParticleKind::FallingNectar => "falling_nectar",
            ParticleKind::Ash => "ash",
            ParticleKind::CrimsonSpore => "crimson_spore",
            ParticleKind::WarpedSpore => "warped_spore",
            ParticleKind::DrippingObsidianTear => "dripping_obsidian_tear",
            ParticleKind::FallingObsidianTear => "falling_obsidian_tear",
            ParticleKind::LandingObsidianTear => "landing_obsidian_tear",
            ParticleKind::ReversePortal => "reverse_portal",
            ParticleKind::WhiteAsh => "white_ash",
        }
    }
}
